package fileReader.demo.reader;

import java.awt.geom.Point2D;
import java.util.Vector;


/**
 * Deptharea is a map symbol. Polygon that is defined by a set of verteces
 * in which first and last vertex are the same (ring). 
 * Deptharea has depth between minimum and maximum depth. Deptharea may have "holes".
 * Holes are other depth areas inside a mother deptharea.
 */

class DepthArea extends PolygonDrawer
{
	/**
	 * Constructor for the class DeptArea.
	 * Initializes holeList vector. 
	 *
	 */
    public DepthArea()
    {
        holeList = new Vector();
    }

    /**
     * Checks are there intersects.
     * @param cedge edge to check
     * @return boolean true if are intersects else false
     */
   public boolean Intersects(Edge cedge)
    {
    	cedge.setHasColinealPoints(false);
        for(int i = 0; i < vertexList.size(); i++)
        {
            int j = (i + 1) % vertexList.size();
            Edge cedge1 = new Edge((Point2D)vertexList.elementAt(i), (Point2D)vertexList.elementAt(j));
            if(cedge1.Intersects(cedge))//inter2
                return true;
        }
        
        for(int i = 0; i < vertexList.size(); i++)
        {
       		if(IsColineal(cedge,(Point2D)vertexList.elementAt(i))){
            	cedge.setHasColinealPoints(true);
            	return true;
            }
        }
        
        return false;
    }
  
    /**
     * Checks that are there collinneals between edge and vertex
     * @param cedge edge
     * @param cvertex vertex
     * @return boolean true if is else false
     */
    public boolean IsColineal(Edge cedge, Point2D cvertex){
    	
    	double x1,y1,x2,y2,x,y;
    	boolean belong; 
    	
    	belong=false;
    	
    	x1=cedge.getStart().getX();
    	y1=cedge.getStart().getY();
    	
    	x2=cedge.getEnd().getX();
    	y2=cedge.getEnd().getY();
    	
       	x=cvertex.getX();
       	y=cvertex.getY();
    	
		//Rule equation to determine if one vertex is collinear
       	belong=((x2-x1)*y-(y2-y1)*x == ((x2-x1)*y1-(y2-y1)*x1));
       		
       	if (belong){
       			//Check if point belongs to segment
    			if(x1<x2){
    				if (x>x1 && x<x2)
    	    					return true;
    			}
    			else if (x1>x2){ 
    					if (x<x1 && x>x2)
    						return true;
    			}
    			else{ //X1==X2
    					if(y1<y2){
    						if (y>y1 && y<y2)
    							return true;
    					}
    					else if (y1>y2){ 
    						if (y<y1 && y>y2)
    							return true;			
    					}
    				}	
    	}	
      	return false;
    }	
	
  
    /**
     * This method checks that are there vertex inside vertex.
     * @param control vertex control point
     * @param y_translation  y transaltion
     * @param x_translation  x translation
     * @param zoom zoom value
     * @return boolean indicator if control point is inside the polygon
     */
    public boolean Inside(Point2D control)
    {
    	boolean inside = false;
    	int i = vertexList.size();
        int j = 0;
        
        if(boundingBox.inside(control.getX(), control.getY()))
        	inside = true;
        
        for(int k = 0; k < i && inside==true; k++)
        {
        	Point2D cvertex1 = (Point2D)vertexList.elementAt(k);
        	Point2D cvertex2 = (Point2D)vertexList.elementAt(((k + i) - 1)% i);
        	Point2D cvertex3 = (Point2D)vertexList.elementAt((k + 1) % i);
        	Edge cedge = new Edge(cvertex1,cvertex3);

            if(control.getY() == cvertex1.getY()) //Vertex in the same height
            {
                    if(cvertex1.getX()<control.getX()){ // Test only left side of the center point
                            if(cvertex2.getY() >= control.getY() && cvertex3.getY() < control.getY() || cvertex2.getY() < control.getY() && cvertex3.getY() > control.getY()) //Check if i+1,i-1 are up or down
                        j++;
                    }
            }
            else if(cedge.getStart().getY() > control.getY() && cedge.getEnd().getY() < control.getY() || cedge.getStart().getY() < control.getY() && cedge.getEnd().getY() > control.getY())
            {
                double d2 = cedge.GetX(control.getY());
                if(d2 < control.getX())
                    j++;
            }
        }

        if(j%2==0)
        	inside = false;
    	
        return inside;
    }

	/**
     * This method checks if vertex is inside a polygon too shallow
     * @param control vertex control point
     * 
     * @return boolean indicator if control point is inside the polygon
     */
    public boolean Inside(Point2D control, double depthBound)
    {	
    	if(minDepth<depthBound && Inside(control))
    		return true;
    	else 
    		return false;
	}


    /**
     * Check if the edge is one edge of any polygon, if it is,
     * it won't be diagonal!!
     * @param cedge
     * @return boolean
     */    
    public boolean IsDiagonal(Edge cedge)
    {
  	
        int i = vertexList.size();
        // 3 vertexes = triangle, no diagonals
        if(i == 3)
            return false;

	  //Check if the edge is one edge of any polygon, if it is,
      // it won't be diagonal!!
        for(int j = 0; j < i; j++)
        {
            Point2D cvertex = (Point2D)vertexList.elementAt(j);
            int k = j+1;
            if (k==i) 
            	k = 0;
            Edge cedge1 = new Edge (cvertex,
            		(Point2D)vertexList.elementAt(k));
            if(cedge.Equivalent(cedge1))
                return false;
        }

	  //Last checking: is the edge inside the polygon?
	  //Calculate middle point	
        double d = (cedge.getStart().getX() + cedge.getEnd().getX()) / 2D;
        double d1 = (cedge.getStart().getX() + cedge.getEnd().getY()) / 2D;
	  Point2D cvertex1 = new Point2D.Double(d, d1);
	  //Check if middle point is inside the polygon.
        return Inside(cvertex1);
        }
    
      
    /**
	 * This is a setter method for min depth.
	 * 
	 * @param minDepth depth value to set
	 */
	public void setMinDepth(double minDepth){
		this.minDepth = minDepth;
	}
	
	/**
	 * This is a setter method for max depth.
	 * 
	 * @param maxDepth depth value to set
	 */
	public void setMaxDepth(double maxDepth){
		this.maxDepth = maxDepth;
	}
	

	/**
	 * This is a getter method for min depth.
	 * 
	 * @return value of min depth
	 */
	public double getMinDepth(){
		return minDepth;
	}
	
	/**
	 * This is a getter method for max depth.
	 * 
	 * @return value of max depth
	 */
	public double getMaxDepth(){
		return maxDepth;
	}
}